use async_trait::async_trait;
use base32::Alphabet;
use base64::Engine;
use base64::prelude::{BASE64_STANDARD, BASE64_STANDARD_NO_PAD};
use clap::Parser;

use crate::commands::commands::Command;
use crate::models::models;
use crate::models::models::command::CommandState;
use crate::utils::command;

#[derive(Debug, Default, Clone, Parser)]
#[clap(disable_help_flag = true)]
struct Args {
    // 解码
    #[arg(short = 'd', long = "decode", default_value_t = false)]
    decode: bool,
    // 不使用填充
    #[arg(long = "no-padding", default_value_t = false)]
    no_padding: bool,
    // base32编码
    #[arg(long = "32", default_value_t = false)]
    base_32: bool,
    // base32编码时使用RFC4648字符集
    #[arg(long = "rfc4648", default_value_t = false)]
    rfc_4648: bool,
    // RFC4648字符集是否进行填充
    #[arg(long = "padding", default_value_t = false)]
    padding: bool,
    // 字符串
    value: String,
}

#[derive(Debug, Default, Clone)]
pub(crate) struct BaseCommand {}

#[async_trait]
impl Command for BaseCommand {
    async fn execute(&self, command: models::command::Command) -> models::command::Command {
        let args = command::parse_command_args::<Args>(command.args.as_str());
        if args.is_err() {
            return self.save_command_output(command, CommandState::Success, args.unwrap_err().to_string());
        }

        let args = args.unwrap();

        if args.base_32 {
            let mut alphabet = Alphabet::Crockford;
            if args.rfc_4648 {
                alphabet = Alphabet::RFC4648 { padding: args.padding }
            }

            if args.decode {
                let content = base32::decode(alphabet, args.value.as_str());
                if content.is_none() {
                    return self.save_command_output(command, CommandState::Failed, "base32解码失败".to_string());
                }

                return self.save_command_output(command, CommandState::Success, String::from_utf8(content.unwrap()).unwrap());
            }

            return self.save_command_output(command, CommandState::Success, base32::encode(alphabet, args.value.as_bytes()));
        }


        let mut purpose = BASE64_STANDARD;
        if args.no_padding {
            purpose = BASE64_STANDARD_NO_PAD;
        }

        if args.decode {
            let content = purpose.decode(args.value.as_str());
            if content.is_err() {
                return self.save_command_output(command, CommandState::Failed, format!("base64解码失败: {}", content.unwrap_err().to_string()));
            }

            return self.save_command_output(command, CommandState::Success, String::from_utf8(content.unwrap()).unwrap());
        }

        self.save_command_output(command, CommandState::Success, purpose.encode(args.value))
    }
}